home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / seyon / SePort.c < prev    next >
C/C++ Source or Header  |  1995-05-03  |  22KB  |  1,127 lines

  1.  
  2. /*
  3.  * This file is part of the Seyon, Copyright (c) 1992-1993 by Muhammad M.
  4.  * Saggaf. All rights reserved.
  5.  *
  6.  * See the file COPYING (1-COPYING) or the manual page seyon(1) for a full
  7.  * statement of rights and permissions for this program.
  8.  */
  9.  
  10. #include "config.h"
  11.  
  12. #include <signal.h>
  13. #include <fcntl.h>
  14. #include <errno.h>
  15. #include <limits.h>
  16.  
  17. #include <X11/Intrinsic.h>
  18.  
  19. #if HAVE_TERMIOS
  20. #include <termios.h>
  21. #else
  22. #if HAVE_TERMIO
  23. #include <termio.h>
  24. #else
  25. #if HAVE_SGTTYB
  26. #include <sys/ioctl.h>
  27. #endif
  28. #endif
  29. #endif
  30.  
  31. #if LF_USE_DEV_NUMBERS
  32. #include <sys/stat.h>
  33. #ifdef SVR4
  34. #include <sys/mkdev.h>
  35. #else
  36. #include <sys/sysmacros.h>
  37. #endif /* SVR4 */
  38. #endif /* LF_USE_DEV_NUMBERS */
  39.  
  40. #if USE_NONSTD_BAUD
  41. #ifdef linux
  42. #include <sys/ioctl.h>
  43. #include <linux/fs.h>
  44. #include <linux/tty.h>
  45. #endif
  46. #endif
  47.  
  48. #include "seyon.h"
  49. #include "SeDecl.h"
  50.  
  51. #if !defined(O_NDELAY) && defined(O_NONBLOCK)
  52. #define O_NDELAY O_NONBLOCK
  53. #endif
  54.  
  55. #if !defined(MAX_INPUT) && defined(_POSIX_MAX_INPUT)
  56. #define MAX_INPUT _POSIX_MAX_INPUT
  57. #endif
  58.  
  59. extern char TtyReadChar();
  60. extern int  TtyReadStr(),
  61.             TtyTimedReadChar(),
  62.             TtyReadLine(),
  63.             TtyTimedWaitFor(),
  64.             IoGetModemStat();
  65.  
  66. extern speed_t  io_get_speed();
  67.  
  68. /*
  69.  * MDELAY is the delay in the output because (on my modem) the command would be
  70.  * ignored if sent at full speed.  Change for other setups. (This setting is
  71.  * for U.S. Robotics Password Modem).
  72.  */
  73.  
  74. #if HAVE_TERMIOS
  75. static struct termios pmode;    /* modem device control structure */
  76. #else
  77. #if HAVE_TERMIO
  78. static struct termio pmode;        /* modem device control structure */
  79. #else
  80. #if HAVE_SGTTYB
  81. static struct sgttyb pmode;
  82. #endif
  83. #endif
  84. #endif
  85.  
  86. char            modem_port[REG_BUF]; /* modem port device file string */
  87. static int      mfd = -1;        /* modem port file descriptor */
  88. int             baudrate = B9600; /* baud rate */
  89.  
  90. void
  91. MdmIFlush()
  92. {
  93.   int TtyIFlush();
  94.   TtyIFlush(mfd);
  95. }
  96.  
  97. void
  98. MdmOFlush()
  99. {
  100.   int TtyOFlush();
  101.   TtyOFlush(mfd);
  102. }
  103.  
  104. void
  105. MdmIOFlush()
  106. {
  107.   int TtyIOFlush();
  108.   TtyIOFlush(mfd);
  109. }
  110.  
  111. void
  112. send_break()
  113. {
  114.   io_send_break(mfd);
  115. }
  116.  
  117. void
  118. MdmPutString(s)
  119.      char           *s;
  120. {
  121.   char            c;
  122.  
  123.   usleep(MDELAY);
  124.   for (; (c = *s); s++) {
  125.     if (*s == '^' && *(s + 1))
  126.       if (*(++s) == '^') c = *s;
  127.       else c = *s & 0x1f;
  128.  
  129.     if (c == '~') sleep(1);
  130.     else send_tbyte(c);
  131.     usleep(MDELAY);
  132.   }
  133. }
  134.  
  135. void
  136. mprintf(fmt, a, b, c)
  137.      char           *fmt,
  138.                     *a,
  139.                     *b,
  140.                     *c;
  141. {
  142.   char            buf[REG_BUF];
  143.  
  144.   sprintf(buf, fmt, a, b, c);
  145.   MdmPutString(buf);
  146. }
  147.  
  148. void
  149. get_modem_attr()
  150. {
  151.   io_get_attr(mfd, &pmode);
  152.   baudrate = io_get_speed(&pmode);
  153. }
  154.  
  155. void
  156. set_modem_attr()
  157. {
  158.   io_set_speed(&pmode, baudrate);
  159.   io_set_attr(mfd, &pmode);
  160. }
  161.  
  162. int
  163. get_modem_fio()
  164. {
  165.   return fcntl(mfd, F_GETFL);
  166. }
  167.  
  168. void
  169. set_modem_fio(fio)
  170.      int             fio;
  171. {
  172.   fcntl(mfd, F_SETFL, fio);
  173. }
  174.  
  175.  
  176. /*---------------------------------------------------------------------------+
  177. | MdmSaveRestoreAttr - saves or restores the modem attributes.
  178. +---------------------------------------------------------------------------*/
  179.  
  180. int
  181. MdmSaveRestoreAttr(action)
  182.      int action;
  183. {
  184. #if HAVE_TERMIOS
  185.   static struct termios savedAttr;
  186. #else
  187. #if HAVE_TERMIO
  188.   static struct termio savedAttr;
  189. #else
  190. #if HAVE_SGTTYB
  191.   static struct sgttyb savedAttr;
  192. #endif
  193. #endif
  194. #endif
  195.  
  196.   if (mfd == -1) return -1;
  197.  
  198.   if (action == ATTR_SAVE)
  199.     return io_get_attr(mfd, &savedAttr);
  200.   else if (action == ATTR_RESTORE) {
  201.     /* Not sure how to do this with sgttyb */
  202. #if HAVE_TERMIOS || HAVE_TERMIO
  203.     savedAttr.c_cflag &= ~HUPCL; /* don't hangup on closing */
  204. #endif
  205.     return io_set_attr(mfd, &savedAttr);
  206.   }
  207.  
  208.   return -1;
  209. }
  210.  
  211. int
  212. GetModemStat(newModem)
  213.      int             newModem;
  214. {
  215.   static Boolean  useModemControl = True;
  216.   int             retStat;
  217.  
  218.   if (newModem) useModemControl = True;
  219.  
  220.   if (useModemControl && (retStat = IoGetModemStat(mfd)) < 0) {
  221.     SeErrorF("Could not get control line status for device %s", 
  222.              modem_port, "", "");
  223.     SeNotice("Disabling status toggles for that device");
  224.     useModemControl = False;
  225.     qres.ignoreModemDCD = True;
  226.     PopupError("errModemControl", NULL);
  227.   }
  228.   
  229.   return (useModemControl ?  retStat : 0);
  230. }
  231.  
  232. int
  233. Online()
  234. {
  235.   return((GetModemStat(0) & MDM_DCD) ? 1 : 0);
  236. }
  237.  
  238. void
  239. cancel_dial(verbose)
  240.      int             verbose;
  241. {
  242.   MdmPutString(qres.dialCancelString);
  243.   MdmPurge();
  244.  
  245.   if (verbose)
  246.     SeyonMessage("Canceled");
  247. }
  248.  
  249. void
  250. SetInitialModemAttr()
  251. {
  252. #if HAVE_TERMIOS || HAVE_TERMIO
  253.   pmode.c_iflag |= (IGNBRK | IGNPAR);
  254.   pmode.c_iflag &= ~(ISTRIP | BRKINT);
  255.   pmode.c_lflag = 0;
  256.  
  257. #ifdef XCLUDE
  258.   pmode.c_lflag |= XCLUDE;
  259. #endif
  260.  
  261.   pmode.c_oflag &= ~OPOST;        /* transparent output */
  262.   pmode.c_cflag = baudrate | CREAD | CLOCAL;
  263.  
  264.   /* this many characters satisfy reads */
  265.   pmode.c_cc[VMIN] = min(qres.modemVMin, MAX_INPUT);
  266.   pmode.c_cc[VTIME] = 1;        /* or in this many tenths of a second */
  267. #else
  268. #if HAVE_SGTTYB
  269.   pmode.sg_flags = RAW;
  270. #endif
  271. #endif
  272.  
  273.   xc_setflow();
  274.   set_rtscts();
  275. }
  276.  
  277. void
  278. set_rtscts()
  279. {
  280. #ifdef sco
  281.   if (qres.rtsctsFlowControl) {
  282.     pmode.c_cflag &= ~CLOCAL;
  283.     pmode.c_cflag &= ~ORTSFL;
  284.     pmode.c_cflag |= RTSFLOW | CTSFLOW;
  285.   } else {
  286.     pmode.c_cflag &= ~(ORTSFL | RTSFLOW | CTSFLOW);
  287.   }
  288. #else /* sco */
  289. #ifdef CRTSCTS
  290.   if (qres.rtsctsFlowControl) {
  291.     pmode.c_cflag |= CRTSCTS;
  292.  
  293. #ifdef CNORTSCTS
  294.     pmode.c_cflag &= ~CNORTSCTS;
  295. #endif
  296.  
  297.   }
  298.   else {
  299.     pmode.c_cflag &= ~CRTSCTS;
  300.  
  301. #ifdef CNORTSCTS
  302.     pmode.c_cflag |= CNORTSCTS;
  303. #endif
  304.  
  305.   }
  306. #endif
  307. #endif /* sco */
  308.  
  309.   if (mfd != -1)
  310.     io_set_attr(mfd, &pmode);
  311. }
  312.  
  313. void
  314. xc_setflow()
  315. {
  316.   if (qres.xonxoffFlowControl) {
  317.  
  318. #if HAVE_TERMIOS
  319.     pmode.c_iflag |= IXON | IXOFF;
  320. #else
  321. #if HAVE_TERMIO
  322.     pmode.c_iflag |= IXON | IXOFF;
  323.     pmode.c_iflag &= ~IXANY;
  324. #else
  325. #if HAVE_SGTOBTYB
  326.     pmode.sg_flags |= TANDEM;
  327. #endif
  328. #endif
  329. #endif
  330.  
  331.   }
  332.   else
  333. #if HAVE_TERMIOS
  334.     pmode.c_iflag &= ~(IXON | IXOFF);
  335. #else
  336. #if HAVE_TERMIO
  337.     pmode.c_iflag &= ~(IXON | IXOFF);
  338.     pmode.c_iflag &= ~IXANY;
  339. #else
  340. #if HAVE_SGTTYB
  341.     pmode.sg_flags &= ~TANDEM;
  342. #endif
  343. #endif
  344. #endif
  345.  
  346.   if (mfd != -1)
  347.     io_set_attr(mfd, &pmode);
  348. }
  349.  
  350. char           *
  351. mport(s)            /* get/set port string */
  352.      char           *s;
  353. {
  354.   if (s != NULL)
  355.     strcpy(modem_port, s);
  356.   return (modem_port);
  357. }
  358.  
  359. int
  360. MdmSetGetBaud(baudIndex)
  361.      int             baudIndex;
  362. {
  363.   static char    *baud[] = {"0", "300", "1200", "2400", "4800", "9600", 
  364.                               "19200", "38400", "57600", "115200", NULL};
  365.   long            retBaud;
  366.  
  367.   if (baudIndex != -1)
  368.     retBaud = mbaud(baud[baudIndex]);
  369.   else
  370.     retBaud = mbaud(NULL);
  371.  
  372.   for (baudIndex = 0; baud[baudIndex]; baudIndex++)
  373.     if (atol(baud[baudIndex]) == retBaud)
  374.       return baudIndex;
  375.  
  376.   return -1;
  377. }
  378.  
  379. int
  380. MdmSetGetCSize(bits)
  381.      int             bits;
  382. {
  383.   if (bits != -1) {
  384.     switch (bits) {
  385. #if HAVE_TERMIOS || HAVE_TERMIO
  386.     case 5:
  387.       pmode.c_cflag &= ~CSIZE;
  388.       pmode.c_cflag |= CS5;
  389.       MdmSetGetIStrip(1);
  390.       break;
  391.     case 6:
  392.       pmode.c_cflag &= ~CSIZE;
  393.       pmode.c_cflag |= CS6;
  394.       MdmSetGetIStrip(1);
  395.       break;
  396.     case 7:
  397.       pmode.c_cflag &= ~CSIZE;
  398.       pmode.c_cflag |= CS7;
  399.       MdmSetGetIStrip(1);
  400.       break;
  401.     case 8:
  402.       pmode.c_cflag &= ~CSIZE;
  403.       pmode.c_cflag |= CS8;
  404.       MdmSetGetIStrip((int)qres.stripHighBit);
  405.       break;
  406. #else
  407. #if HAVE_SGTTYB
  408.     case 5:
  409.     case 6:
  410.     case 7:
  411.       pmode.sg_flags |= CBREAK;
  412.       pmode.sg_flags &= ~RAW;
  413.       MdmSetGetIStrip(0);
  414.       break;
  415.     case 8:
  416.       pmode.sg_flags |= RAW;
  417.       pmode.sg_flags &= ~CBREAK;
  418.       MdmSetGetIStrip(0);
  419.       break;
  420. #endif
  421. #endif
  422.     default:
  423.       SeErrorF("invalid number of bits: %d", bits, "", "");
  424.       return -1;
  425.     }
  426.     /* io_set_attr is called in  MdmSetGetIStrip */
  427.   }
  428.  
  429.   if (mfd != -1)
  430.     io_get_attr(mfd, &pmode);
  431.  
  432. #if HAVE_TERMIOS || HAVE_TERMIO
  433.   switch (pmode.c_cflag & CSIZE) {
  434.   case CS5:
  435.     return 5;
  436.   case CS6:
  437.     return 6;
  438.   case CS7:
  439.     return 7;
  440.   case CS8:
  441.     return 8;
  442.   default:
  443.     SeError("Consistency error in number of bits");
  444.     return -1;
  445. #else
  446. #if HAVE_SGTTYB
  447.   switch (pmode.sg_flags & CBREAK) {
  448.   case 0:
  449.     return 8;
  450.   default:
  451.     return 7;
  452. #endif
  453. #endif
  454.   }
  455. }
  456.  
  457. int
  458. MdmSetGetParity(parity)
  459.      int             parity;
  460. {
  461.   if (parity != -1) {
  462.     switch (parity) {
  463. #if HAVE_TERMIOS || HAVE_TERMIO
  464.     case 0:
  465.       pmode.c_cflag &= ~PARENB;
  466.       break;
  467.     case 1:
  468.       pmode.c_cflag |= (PARENB | PARODD);
  469.       break;
  470.     case 2:
  471.       pmode.c_cflag |= PARENB;
  472.       pmode.c_cflag &= ~PARODD;
  473.       break;
  474. #else
  475. #if HAVE_SGTTYB
  476.     case 0:
  477.       pmode.sg_flags &= ~ANYP;
  478.       break;
  479.     case 1:
  480.       pmode.sg_flags |= ODDP;
  481.       pmode.sg_flags &= ~EVENP;
  482.       break;
  483.     case 2:
  484.       pmode.sg_flags |= EVENP;
  485.       pmode.sg_flags &= ~ODDP;
  486.       break;
  487. #endif
  488. #endif
  489.     default:
  490.       SeErrorF("Invalid parity: %d", parity, "", "");
  491.       return -1;
  492.     }
  493.     if (mfd != -1)
  494.       io_set_attr(mfd, &pmode);
  495.   }
  496.  
  497.   if (mfd != -1)
  498.     io_get_attr(mfd, &pmode);
  499.  
  500. #if HAVE_TERMIOS || HAVE_TERMIO
  501.   if (!(pmode.c_cflag & PARENB))
  502.     return 0;
  503.   else if (pmode.c_cflag & PARODD)
  504.     return 1;
  505.   else
  506.     return 2;
  507. #else
  508. #if HAVE_SGTTYB
  509.   switch (pmode.sg_flags & ANYP) {
  510.   case ODDP:
  511.     return 1;
  512.   case EVENP:
  513.     return 2;
  514.   default:
  515.     return 0;
  516.   }
  517. #endif
  518. #endif
  519. }
  520.  
  521. int
  522. MdmSetGetIStrip(flag)
  523.      int             flag;
  524. {
  525. #if HAVE_TERMIOS || HAVE_TERMIO
  526.   if (flag != -1) {
  527.     if (flag)
  528.       pmode.c_iflag |= ISTRIP;
  529.     else
  530.       pmode.c_iflag &= ~ISTRIP;
  531.     
  532.     if (mfd != -1)
  533.       io_set_attr(mfd, &pmode);
  534.   }
  535.  
  536.   if (mfd != -1)
  537.     io_get_attr(mfd, &pmode);
  538.  
  539.   if (pmode.c_iflag & ISTRIP)
  540.     return 1;
  541.   else
  542.     return 0;
  543. #else
  544. #if !HAVE_SGTTYB
  545.   if (mfd != -1)
  546.     io_set_attr(mfd, &pmode);
  547.  
  548.   return 0;
  549. #endif
  550. #endif
  551. }
  552.  
  553. int
  554. MdmSetGetStopBits(bits)
  555.      int             bits;
  556. {
  557. #if HAVE_TERMIOS || HAVE_TERMIO
  558.   if (bits != -1) {
  559.     switch (bits) {
  560.     case 1:
  561.       pmode.c_cflag &= ~CSTOPB;
  562.       break;
  563.     case 2:
  564.       pmode.c_cflag |= CSTOPB;
  565.       break;
  566.     default:
  567.       SeErrorF("invalid number of stop bits: %d", bits, "", "");
  568.       return -1;
  569.     }
  570.     if (mfd != -1)
  571.       io_set_attr(mfd, &pmode);
  572.   }
  573.  
  574.   if (mfd != -1)
  575.     io_get_attr(mfd, &pmode);
  576.  
  577.   if (pmode.c_cflag & CSTOPB)
  578.     return 2;
  579.   else
  580.     return 1;
  581. #else
  582. #if !HAVE_SGTTYB
  583.   if (mfd != -1)
  584.     io_set_attr(mfd, &pmode);
  585.  
  586.   return 1;
  587. #endif
  588. #endif
  589. }
  590.  
  591. /*
  592.  * Get/set the baud rate of the modem port. If the port hasn't been opened
  593.  * yet, just store in pmode for mopen() to use when it opens the port.
  594.  */
  595. long
  596. mbaud(s)
  597.      char           *s;
  598. {
  599. #if USE_NONSTD_BAUD
  600. #ifdef linux
  601.   static struct serial_struct ser_io;
  602.  
  603.   if (ioctl(mfd, TIOCGSERIAL, &ser_io) < 0) {
  604.     SePError("Could not get linux serial info");
  605.     return -1;
  606.   }
  607. #endif
  608. #endif
  609.  
  610.   if (s != NULL) {
  611.     /* this gives a more limited, realistic */
  612.     switch (atol(s)) {           /* range than in sgtty.h */
  613.     case 300:
  614.       baudrate = B300;
  615.       break;
  616.     case 1200:
  617.       baudrate = B1200;
  618.       break;
  619.     case 2400:
  620.       baudrate = B2400;
  621.       break;
  622.     case 4800:
  623.       baudrate = B4800;
  624.       break;
  625.     case 9600:
  626.       baudrate = B9600;
  627.       break;
  628.     case 19200:
  629.       baudrate = B19200;
  630.       break;
  631.     case 38400:
  632.       baudrate = B38400;
  633. #if USE_NONSTD_BAUD
  634. #ifdef linux
  635.       ser_io.flags &= ~ASYNC_SPD_MASK;
  636. #endif
  637. #endif
  638.       break;
  639. #if USE_NONSTD_BAUD
  640. #ifdef linux
  641.     case 57600:
  642.       baudrate = B38400;
  643.       ser_io.flags &= ~ASYNC_SPD_MASK;
  644.       ser_io.flags |= ASYNC_SPD_HI;
  645.       break;
  646.     case 115200:
  647.       baudrate = B38400;
  648.       ser_io.flags &= ~ASYNC_SPD_MASK;
  649.       ser_io.flags |= ASYNC_SPD_VHI;
  650.       break;
  651. #endif
  652. #endif
  653.     default:
  654.       return (-1);
  655.     }
  656.     io_set_speed(&pmode, baudrate);
  657.     if (mfd != -1) {
  658.       io_set_attr(mfd, &pmode);
  659. #if USE_NONSTD_BAUD
  660. #ifdef linux
  661.       if (baudrate == B38400)
  662.     if (ioctl(mfd, TIOCSSERIAL, &ser_io) < 0) {
  663.       SePError("Could not set linux serial info");
  664.       return -1;
  665.     }
  666. #endif
  667. #endif
  668.     }
  669.   }
  670.  
  671.   if (mfd != -1)
  672.     io_get_attr(mfd, &pmode);
  673.  
  674.   switch (io_get_speed(&pmode)) {
  675.   case B300:
  676.     return (300);
  677.   case B1200:
  678.     return (1200);
  679.   case B2400:
  680.     return (2400);
  681.   case B4800:
  682.     return (4800);
  683.   case B9600:
  684.     return (9600);
  685.   case B19200:
  686.     return (19200);
  687.   case B38400:
  688. #if USE_NONSTD_BAUD
  689. #ifdef linux
  690.     if (mfd != -1)
  691.       if (ioctl(mfd, TIOCGSERIAL, &ser_io) < 0) {
  692.         SePError("Could not get linux serial info");
  693.         return -1;
  694.       }
  695.  
  696.     if ((ser_io.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
  697.       return 115200;
  698.     else if ((ser_io.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
  699.       return 57600;
  700.     else
  701. #endif
  702. #endif
  703.       return 38400;
  704.   }
  705.  
  706.   SeError("Consistency error in baud rate");
  707.   return -1;
  708. }
  709.  
  710. /*
  711.  * The following routine is used to hang up the modem.  This is accomplished
  712.  * by setting the baud rate to 0.  According to my documentation on termio,
  713.  * setting the baud rate to zero will result in DTR not being asserted. This
  714.  * hangs up some (most?) modems.  If not, the second part of the routine
  715.  * sends the Hayes modem "escape" and then a hangup command.
  716.  */
  717.  
  718. void
  719. MdmHangup()
  720. {
  721.   int terminalWasActive;
  722. #ifdef sco
  723.   int old_cflag;
  724. #endif
  725.  
  726.   if (mfd == -1) return;
  727.  
  728.   terminalWasActive = SuspContTerminal(TERM_SUSPEND);
  729.   if (qres.hangupViaDTR) {
  730. #ifdef sco
  731.     old_cflag = pmode.c_cflag;
  732. #endif
  733.     io_set_speed(&pmode, B0);    /* set baud 0 (drop DTR) */
  734.     io_set_attr(mfd, &pmode);
  735.  
  736.     sleep(1);                    /* wait a second */
  737.  
  738.     io_set_speed(&pmode, baudrate);    /* reset baud rate */
  739. #ifdef sco
  740.     pmode.c_cflag |= CLOCAL;
  741. #endif
  742.     io_set_attr(mfd, &pmode);
  743. #ifdef sco
  744.     pmode.c_cflag = old_cflag;
  745.     io_set_attr(mfd, &pmode);
  746. #endif
  747.  
  748.   }
  749.   else {                        /* use Hayes command */
  750.     sleep(2);                    /* allow for "escape guard time" */
  751.     MdmPutString(qres.modemAttentionString); /* send modem escape command */
  752.  
  753.     sleep(3);                    /* more "escape guard time" */
  754.     MdmPutString(qres.modemHangupString); /* send hangup command */
  755.   }
  756.   MdmPurge();
  757.   if (terminalWasActive) SuspContTerminal(TERM_CONTINUE);
  758.   
  759.   UpdateStatusBox(NULL);
  760. }
  761.  
  762.   
  763. /*
  764.  * Opens the modem port and configures it. Returns 0 for success or -1 on
  765.  * error.
  766.  */
  767.  
  768. int
  769. OpenModem(modem)
  770.      String modem;
  771. {
  772.   int             LockModem(),
  773.                   UnlockModem();
  774.   void            MdmIOFlush();
  775.   int             oldFlags;
  776.  
  777.   if (modem == NULL || modem[0] == '\0') return ERR_MDM_NOMODEM;
  778.   if (LockModem(modem)) return ERR_MDM_LOCKED;
  779.  
  780.   /* Need O_NDELAY to get the file open before we have carrier */
  781.   if ((mfd = open(modem, O_RDWR | O_NDELAY)) < 0) 
  782.     {UnlockModem(modem); return ERR_MDM_OPENFAILED;}
  783.  
  784.   /* Now, we must reset the O_NDELAY mode so that read() works correctly */
  785.   if (((oldFlags = fcntl(mfd, F_GETFL, 0)) == -1) ||
  786.       (fcntl(mfd, F_SETFL, oldFlags & ~O_NDELAY) == -1)) 
  787.     {UnlockModem(modem); return ERR_MDM_RESETFLAGSFAILED;}
  788.  
  789. #if HAVE_SGTTYB
  790.   if (ioctl(mfd, TIOCEXCL) < 0)
  791.     SePError("exclusive-use");
  792. #endif
  793.  
  794.   mport(modem);
  795.  
  796.   MdmIOFlush();
  797.   MdmSaveRestoreAttr(ATTR_SAVE);
  798.   SetInitialModemAttr();
  799.   io_set_attr(mfd, &pmode);
  800.  
  801.   GetModemStat(1);
  802.  
  803.   if (mbaud(qres.defaultBPS) == -1)
  804.     se_warningf("invalid default BPS value: %s", qres.defaultBPS, "", "");
  805.   if (MdmSetGetCSize(qres.defaultBits) < 0)
  806.     se_warningf("invalid default number of bits: %s", qres.defaultBits, 
  807.                 "", "");
  808.   if (MdmSetGetParity(qres.defaultParity) < 0)
  809.     se_warningf("invalid default parity value: %s", qres.defaultParity, 
  810.                 "", "");
  811.   if (MdmSetGetStopBits(qres.defaultStopBits) < 0)
  812.     se_warningf("invalid default number of stop bits: %s",
  813.                 qres.defaultStopBits, "", "");
  814.  
  815.   return 0;
  816. }
  817.  
  818. void
  819. ShowOpenModemErrMsg(modemName, retStatus)
  820.      String    modemName;
  821.      int       retStatus;
  822. {
  823.   switch(retStatus) {
  824.   case ERR_MDM_NOMODEM:
  825.     SeError("No Modem Specified");
  826.     break;
  827.   case ERR_MDM_LOCKED:
  828.     SeError(FmtString("Modem ``%s'' is Locked", modemName, "", ""));
  829.     break;
  830.   case ERR_MDM_OPENFAILED:
  831.     SePError(FmtString("Unable to Open Modem ``%s''", modemName, "", ""));
  832.     break;
  833.   case ERR_MDM_RESETFLAGSFAILED:
  834.     SePError(FmtString("Unable to Reset Flags for Modem ``%s''", 
  835.                        modemName, "", ""));
  836.     break;
  837.   default:
  838.     SeError(FmtString("Unknown Error While Openeong Modem ``%s''", 
  839.                       modemName, "", ""));
  840.     break;
  841.   }
  842. }
  843.  
  844. int
  845. CloseModem()
  846. {
  847.   if (mfd == -1) return -1;
  848.   MdmSaveRestoreAttr(ATTR_RESTORE);
  849.   close(mfd);
  850.   return 0;
  851. }
  852.  
  853. /*
  854.  * Attach standard input and output to the modem port. This only gets called
  855.  * after a fork by the child process; which then exec's a program that uses
  856.  * standard i/o for some data transfer protocol. (To put this here is
  857.  * actually a kludge, but I wanted to keep the modem-specific stuff in a
  858.  * black box.)
  859.  */
  860. void
  861. mattach()
  862. {
  863.   extern int dup2();
  864.   /*
  865.    * attach standard i/o to port
  866.    */
  867.   dup2(mfd, 0);                    /* close local stdin and connect to port */
  868.   dup2(mfd, 1);                    /* close local stdout and connect to port */
  869.  
  870.   close(mfd);                    /* close the old port descriptor */
  871. }
  872.  
  873. /* ------------------------------------------------------------
  874.  * Routines to read from the modem.
  875.  */
  876.  
  877. /*
  878.  * MdmReadStr: reads a bunch of characters from the modem.
  879.  */
  880.  
  881. int
  882. MdmReadStr(buf)
  883.      char           *buf;
  884. {
  885.   return TtyReadStr(mfd, buf);
  886. }
  887.  
  888. /*
  889.  * MdmReadChar: reads one character from the modem.
  890.  */
  891.  
  892. char
  893. MdmReadChar(readChar)
  894.      char           *readChar;
  895. {
  896.   return TtyReadChar(mfd, readChar);
  897. }
  898.  
  899. int
  900. MdmTimedReadChar(readChar, expireTime)
  901.      char           *readChar;
  902.      int             expireTime;
  903. {
  904.   return TtyTimedReadChar(mfd, readChar, expireTime);
  905. }
  906.  
  907. /*
  908.  * MdmReadLine: reads one line from the modem.
  909.  */
  910.  
  911. int
  912. MdmReadLine(buf)
  913.      char           *buf;
  914. {
  915.   return TtyReadLine(mfd, buf);
  916. }
  917.  
  918. int
  919. MdmTimedWaitFor(expectedString, waitTime)
  920.      char           *expectedString;
  921.      int             waitTime;
  922. {
  923.   return TtyTimedWaitFor(mfd, expectedString, waitTime);
  924. }
  925.  
  926. /*
  927.  * MdmPurge: throws away all incoming characters until no more are sent.
  928.  */
  929.  
  930. void
  931. MdmPurge()
  932. {
  933.   char            c;
  934.   while (MdmTimedReadChar(&c, 1) >= 0);
  935. }
  936.  
  937. #ifdef retired
  938. int
  939. readbyte(seconds)
  940.      int             seconds;
  941. {
  942.   return trminp(mfd, seconds);
  943. }
  944. #endif
  945.  
  946. /*
  947.  *    Output a byte to the modem port. All data sent to the modem
  948.  *    is output through this routine.
  949.  */
  950.  
  951. void
  952. sendbyte(ch)
  953.      int             ch;
  954. {
  955.   char            c = ch & 0xff;
  956.  
  957.   if (write(mfd, &c, 1) < 0)
  958.     SePError("character write");
  959. }
  960.  
  961. void
  962. sendf_slowly(format, a, b, c)
  963.      char           *format,
  964.                     *a,
  965.                     *b,
  966.                     *c;
  967. {
  968.   char            buffer[SM_BUF];
  969.  
  970.   sprintf(buffer, format, a, b, c);
  971.   send_slowly(buffer);
  972. }
  973.  
  974. void
  975. send_slowly(s)
  976.      char           *s;
  977. {
  978.   while (*s) {
  979.     sendbyte(*s++);
  980.     /*
  981.      * avoid busy waiting by using usleep if available. adjust MDELAY if
  982.      * you're having trouble
  983.      */
  984.     usleep(MDELAY);
  985.   }
  986. }
  987.  
  988. /*
  989.  * lock_tty() returns non-zero if the lock file exists (prevents Seyon from
  990.  * running).
  991.  *
  992.  * unlock_tty() deletes the lock file.
  993.  *
  994.  * Simple, eh?
  995.  */
  996.  
  997. char            lckf[SM_BUF];
  998. char            ltmp[SM_BUF];
  999. pid_t           lockPid;
  1000.  
  1001. int
  1002. LockModem(modem)
  1003.      String modem;
  1004. {
  1005.   strcpy(modem_port, modem);
  1006.   return lock_tty();
  1007. }
  1008.  
  1009. int
  1010. UnlockModem(modem)
  1011.      String modem;
  1012. {
  1013.   unlock_tty();
  1014.   return 0;
  1015. }
  1016.  
  1017. int
  1018. lock_tty()
  1019. {
  1020.   int             lfd;
  1021.   pid_t           pid,
  1022.                   lckpid;
  1023.   char           *modemname;
  1024. #if LF_USE_ASCII_PID
  1025.   char            pidstr[20],
  1026.                   lckpidstr[20];
  1027.   int             nb;
  1028. #endif
  1029. #if LF_LOWERCASE
  1030.   char        final;
  1031. #endif
  1032. #if LF_USE_DEV_NUMBERS
  1033.   struct stat  mbuf;
  1034. #endif
  1035.  
  1036.   /* Get our PID, and initialize the filename strings */
  1037.   pid = getpid();
  1038.  
  1039. #if !LF_USE_DEV_NUMBERS
  1040.   modemname = strrchr(modem_port, '/');
  1041.   sprintf(lckf, "%s/%s%s", LF_PATH, LF_PREFIX, 
  1042.           (modemname ? (modemname + 1) : modem_port));
  1043.  
  1044. #if LF_LOWERCASE
  1045.   final = lckf[strlen(lckf)-1];
  1046.   final = tolower(final);
  1047.   lckf[strlen(lckf)-1] = final;
  1048. #endif
  1049.  
  1050. #else
  1051.   if(stat(modem_port, &mbuf) < 0) {
  1052.     SePErrorF("could not stat modem port %s", modem_port, "", "");
  1053.     return -1;
  1054.   }
  1055.   sprintf(lckf,"%s/%s%03u.%03u.%03u", LF_PATH, LF_PREFIX, major(mbuf.st_dev),
  1056.           major(mbuf.st_rdev), minor(mbuf.st_rdev));
  1057. #endif /* LF_USE_DEV_NUMBERS */
  1058.  
  1059.   sprintf(ltmp, "%s/%s%d", LF_PATH, "LTMP.", pid);
  1060.   /* Create the LTMP.<pid> file and scribble our PID in it */
  1061.   unlink(ltmp);
  1062.   if ((lfd = creat(ltmp, 0644)) == -1) {
  1063.     SePErrorF("Could not create temporary lock file %s", ltmp, "", "");
  1064.     return -1;
  1065.   }
  1066.  
  1067. #if LF_USE_ASCII_PID
  1068.   sprintf(pidstr, "%10d\n", pid);
  1069.   write(lfd, pidstr, 11);
  1070. #else
  1071.   write(lfd, (char*)&pid, sizeof(pid));
  1072. #endif
  1073.   close(lfd);
  1074.  
  1075.   /*
  1076.    * Attempt to link directly - if it works, we're done.
  1077.    */
  1078. relink:
  1079.   if (link(ltmp, lckf) == 0) {
  1080.     unlink(ltmp);
  1081.     lockPid = pid;
  1082.     return 0;
  1083.   }
  1084.  
  1085.   /*
  1086.    * Oh brother, there's a LCK..* file already; we must now expend effort to
  1087.    * learn if it's stale or not.
  1088.    */
  1089.   if ((lfd = open(lckf, O_RDONLY)) != -1) {
  1090.  
  1091. #if LF_USE_ASCII_PID
  1092.     for (nb = 0; nb < 20 && read(lfd, lckpidstr + nb, sizeof(char)); nb++);
  1093.     if (nb) {
  1094.       lckpid = atol(lckpidstr);
  1095. #else
  1096.     if (read(lfd, (char *)&lckpid, sizeof(lckpid)) == sizeof(lckpid)) {
  1097. #endif
  1098.  
  1099.       lockPid = (pid_t) lckpid;
  1100.       if (kill(lckpid, 0) == 0) {
  1101.         SeErrorF("Device %s is locked by process %d", modem_port, lckpid, "");
  1102.         unlink(ltmp);
  1103.         return -1;
  1104.       }
  1105.     }
  1106.   }
  1107.  
  1108.   /*
  1109.    * The LCK..* file was stale.  Remove and retry.
  1110.    */
  1111.   if (unlink(lckf)) {
  1112.     SePErrorF("Unable to unlink stale lock file \"%s\"", lckf, "", "");
  1113.     unlink(ltmp);
  1114.     return -1;
  1115.   }
  1116.   goto relink;
  1117.   /* NOTREACHED */
  1118. }
  1119.  
  1120. void
  1121. unlock_tty()
  1122. {
  1123.   /* Don't remove the lock file unless it's the one we created */
  1124.   if (getpid() == lockPid)
  1125.     unlink(lckf);
  1126. }
  1127.